#pragma once
#include <iostream>
#include "Socket.hpp"
#include <poll.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

#include "Log.hpp"
extern Log lg;

// 默认端口号
static const uint16_t defaultport = 8080;

static const int fd_num_max = 64; // 辅助数组的最大长度
const int defaultfd = -1;         // 辅助数组中 fd 的默认值
const int non_event = 0;          // 辅助数组中 events && revents 的默认值

class PollServer
{
public:
    PollServer(uint16_t port = defaultport)
        : _port(port)
    {
        // 初始化辅助数组
        for (int i = 0; i < fd_num_max; i++)
        {
            _event_fds[i].fd = defaultfd;
            _event_fds[i].events = non_event;
            _event_fds[i].revents = non_event;
        }
    }

    bool Init()
    {
        _listensock.Socket();
        _listensock.Bind(_port);
        _listensock.Listen();

        return true;
    }

    void PrintFd()
    {
        std::cout << "online fd list: ";
        for (int i = 0; i < fd_num_max; i++)
        {
            if (_event_fds[i].fd == defaultfd) continue;
            std::cout << _event_fds[i].fd << " ";
        }
        std::cout << std::endl;
    }

    void HandlerEvent()
    {
        for (int i = 0; i < fd_num_max; i++)
        {
            int fd = _event_fds[i].fd;
            if (fd == defaultfd) continue;

            // 事件已经就绪
            if(_event_fds[i].revents & POLLIN)
            {
                // 当前 fd 是监听套接字
                if (fd == _listensock.Fd())
                {
                    // 连接事件已经就绪
                    std::string clientip;
                    uint16_t clientport = 0;

                    // 会在这里阻塞吗?不会
                    int sock = _listensock.Accept(&clientip, &clientport); 
                    // 获取 sock 后不能直接 read, 因为可能不会立刻发送数据 -> 交由 poll 关心
                    // 服务器接受一个新的客户端连接（sock）之后，不应该立即尝试从这个新的套接字读取数据。
                    // 原因是客户端可能不会立即发送数据，如果服务器立即尝试读取，那么读取操作可能会阻塞，因为没有任何数据可读。
                    if (sock < 0) return;
                    lg(Info, "accept success, %s:%d, sockfd: %d", clientip.c_str(), clientport, sock);

                    // 找到一个最新的 pos 来放置 sock
                    int pos = 1;
                    for(; pos < fd_num_max; pos++)
                    {
                        if (_event_fds[pos].fd != defaultfd) continue;
                        else break;
                    }
                    if (pos == fd_num_max) // 服务器已满，可以进行扩容操作
                    {
                        lg(Warning, "server is full, close %d now!", sock);
                        close(sock);
                    }
                    else // 将 sock 设置进 fd_array 中
                    {
                        _event_fds[pos].fd = sock;
                        _event_fds[pos].events = POLLIN;
                        _event_fds[pos].revents = non_event;
                        PrintFd(); // 打印正在使用的 sockfd
                    }
                } 
                else // 当前 fd 不是监听套接字
                {
                    char buffer[1024];
                    ssize_t n = read(fd, buffer, sizeof(buffer)-1);
                    if(n > 0)
                    {
                        buffer[n] = 0;
                        std::cout << "get a messge: " << buffer << std::endl;
                    }
                    else if(n == 0)
                    {
                        lg(Info, "client quit, me too, close fd %d", fd);
                        close(fd);
                        _event_fds[i].fd = defaultfd; 
                    }
                    else
                    {
                        lg(Warning, "recv error: fd is %d", fd);
                        close(fd);
                        _event_fds[i].fd = defaultfd; 
                    }
                }       
            }
        }        
    }

    void Start()
    {
        _event_fds[0].fd = _listensock.Fd();
        _event_fds[0].events = POLLIN;
        int timeout = 3000;// 3s
        for (;;)
        {
            int n = poll(_event_fds, fd_num_max, timeout);
            switch(n)
            {
            case 0:
                lg(Info, "time out...");
                break;
            case -1:
                lg(Error, "poll error");
                break;
            default:
                lg(Info, "get a new link!");
                HandlerEvent();
                break;
            }
        }
    }

    ~PollServer()
    {
        _listensock.Close();
    }
private:
    Sock _listensock;                      // 监听套接字
    uint16_t _port;                        // 端口号
    struct pollfd _event_fds[fd_num_max];  // 辅助数组
};
